﻿using System;
using System.Collections.Generic;
using System.Collections;
using Bling.Util;
using Bling.DSL;
using Bling.Core;
using Bling.Vecs;

namespace Bling.Core {
  using Bling.Shaders;
  public class X : Y {
    public override int Index { get { return 0; } }
  }
  public class Y : Z {
    public override int Index { get { return 1; } }
  }
  public class Z : W {
    public override int Index { get { return 2; } }
  }
  public class W {
    public virtual int Index { get { return 3; } }
  }
  public partial interface IValueBrandKS<K, SCALAR> where SCALAR : ValueBrand<K, SCALAR, K, D1, SCALAR> {
    FlexBl<K, DX, SCALAR> Swizzle<DX>(params int[] Indices) where DX : Dim<DX>;
  }
  public abstract partial class BaseValueBrand<T, BRAND, K, D, SCALAR> : ValueBrand<T, BRAND, K, D>, IValueBrand<BRAND, D, SCALAR>, IValueBrandKS<K, SCALAR>
    where BRAND : ValueBrand<T, BRAND, K, D, SCALAR>
    where D : Dim<D>
    where SCALAR : ValueBrand<K, SCALAR, K, D1, SCALAR> {
    public partial class SwizzleOp<DX> : Ops.BaseOperatorX<IVec<K, D>, IVec<K, DX>> where DX : Dim<DX> {
      private readonly int[] Indices;
      public SwizzleOp(int[] Indices) { this.Indices = Indices; }
      public override SmartString Format(SmartString s) {
        string[] Codes = { "x", "y", "z", "w" };
        var ret = ".";
        for (int i = 0; i < Indices.Length; i++) {
          ret = ret + ((Indices[i] < Codes.Length) ? Codes[Indices[i]] : ("_" + Indices[i]));
        }
        return s + ret;
      }
      public override bool IsCheap {
        get { return true; }
      }
      public override Func<SmartString, SmartString> Shader<EVAL>(BaseShaderEval<EVAL> txt, Ops.Operation<IVec<K, D>, IVec<K, DX>> op) {
        return Format;
      }

      public override int GetHashCode() {
        var hc = 0;
        for (int i = 0; i < Indices.Length; i++) hc += (i + 1) * Indices[i];
        return hc;
      }
      public override bool Equals(object obj) {
        if (obj is SwizzleOp<DX>) {
          var other = (SwizzleOp<DX>)obj;
          for (int i = 0; i < Indices.Length; i++)
            if (Indices[i] != other.Indices[i]) return false;
          return true;
        }
        return base.Equals(obj);
      }
      public override Expr<IVec<K, DX>> Expand(Expr<IVec<K, D>> argA) {
        var Es = new Expr<K>[Dim<DX>.Count];
        for (int i = 0; i < Indices.Length; i++) {
          Es[i] = ToBrandD(argA)[Indices[i]];
        }
        return Composite<K, DX>.Make(Es);
      }
    }
    public FlexBl<K, DX, SCALAR> Swizzle<DX>(params int[] Indices) where DX : Dim<DX> {
      return new FlexBl<K, DX, SCALAR>(new SwizzleOp<DX>(Indices).Make(this));
    }
  }
  public static partial class Swizzles {

    public static FlexBl<K,D2,SCALAR> Sw<A, B, K, SCALAR>(this IHasXY<K,SCALAR> V)
      where A : Y, new()
      where B : Y, new()
      where SCALAR : ValueBrand<K, SCALAR, K, D1, SCALAR> {
      var Idx = new int[2];
      Idx[0] = (new A()).Index;
      Idx[1] = (new B()).Index;
      return V.Swizzle<D2>(Idx);
    }
    public static FlexBl<K, D2, SCALAR> Sw<A, B, K, SCALAR>(this IHasXYZ<K, SCALAR> V)
      where A : Z, new()
      where B : Z, new()
      where SCALAR : ValueBrand<K, SCALAR, K, D1, SCALAR> {
      var Idx = new int[2];
      Idx[0] = (new A()).Index;
      Idx[1] = (new B()).Index;
      return V.Swizzle<D2>(Idx);
    }
    public static FlexBl<K, D2, SCALAR> Sw<A, B, K, SCALAR>(this IHasXYZW<K, SCALAR> V)
      where A : W, new()
      where B : W, new()
      where SCALAR : ValueBrand<K, SCALAR, K, D1, SCALAR> {
      var Idx = new int[2];
      Idx[0] = (new A()).Index;
      Idx[1] = (new B()).Index;
      return V.Swizzle<D2>(Idx);
    }
    public static FlexBl<K, D3, SCALAR> Sw<A, B, C, K, SCALAR>(this IHasXY<K, SCALAR> V)
      where A : Y, new()
      where B : Y, new()
      where C : Y, new()
      where SCALAR : ValueBrand<K, SCALAR, K, D1, SCALAR> {
      var Idx = new int[3];
      Idx[0] = (new A()).Index;
      Idx[1] = (new B()).Index;
      Idx[2] = (new C()).Index;
      return V.Swizzle<D3>(Idx);
    }
    public static FlexBl<K, D3, SCALAR> Sw<A, B, C, K, SCALAR>(this IHasXYZ<K, SCALAR> V)
      where A : Z, new()
      where B : Z, new()
      where C : Z, new()
      where SCALAR : ValueBrand<K, SCALAR, K, D1, SCALAR> {
      var Idx = new int[3];
      Idx[0] = (new A()).Index;
      Idx[1] = (new B()).Index;
      Idx[2] = (new C()).Index;
      return V.Swizzle<D3>(Idx);
    }
    public static FlexBl<K, D3, SCALAR> Sw<A, B, C, K, SCALAR>(this IHasXYZW<K,SCALAR> V)
      where A : W, new()
      where B : W, new()
      where C : W, new()
      where SCALAR : ValueBrand<K, SCALAR, K, D1, SCALAR> {
      var Idx = new int[3];
      Idx[0] = (new A()).Index;
      Idx[1] = (new B()).Index;
      Idx[2] = (new C()).Index;
      return V.Swizzle<D3>(Idx);
    }
    public static FlexBl<K, D4, SCALAR> Sw<A, B, C, D, K, SCALAR>(this IHasXY<K,SCALAR> V)
      where A : Y, new()
      where B : Y, new()
      where C : Y, new()
      where D : Y, new()
      where SCALAR : ValueBrand<K, SCALAR, K, D1, SCALAR> {
      var Idx = new int[3];
      Idx[0] = (new A()).Index;
      Idx[1] = (new B()).Index;
      Idx[2] = (new C()).Index;
      Idx[3] = (new D()).Index;
      return V.Swizzle<D4>(Idx);
    }
    public static FlexBl<K, D4, SCALAR> Sw<A, B, C, D, K, SCALAR>(this IHasXYZ<K,SCALAR> V)
      where A : Z, new()
      where B : Z, new()
      where C : Z, new()
      where D : Z, new()
      where SCALAR : ValueBrand<K, SCALAR, K, D1, SCALAR> {
      var Idx = new int[3];
      Idx[0] = (new A()).Index;
      Idx[1] = (new B()).Index;
      Idx[2] = (new C()).Index;
      Idx[3] = (new D()).Index;
      return V.Swizzle<D4>(Idx);
    }
    public static FlexBl<K, D4, SCALAR> Sw<A, B, C, D, K, SCALAR>(this IHasXYZW<K,SCALAR> V)
      where A : W, new()
      where B : W, new()
      where C : W, new()
      where D : W, new()
      where SCALAR : ValueBrand<K, SCALAR, K, D1, SCALAR> {
      var Idx = new int[3];
      Idx[0] = (new A()).Index;
      Idx[1] = (new B()).Index;
      Idx[2] = (new C()).Index;
      Idx[3] = (new D()).Index;
      return V.Swizzle<D4>(Idx);
    }

    public static FlexBl<K,D2,SCALAR> XX<K,SCALAR>(this IHasX<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Swizzle<D2>(0,0); }
    public static FlexBl<K,D3,SCALAR> XXX<K,SCALAR>(this IHasX<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Swizzle<D3>(0, 0, 0); }
    public static FlexBl<K,D4,SCALAR> XXXX<K,SCALAR>(this IHasX<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Swizzle<D4>(0, 0, 0, 0); }
    public static FlexBl<K,D2,SCALAR> YY<K,SCALAR>(this IHasXY<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Y, Y, K, SCALAR>(); }
    public static FlexBl<K,D3,SCALAR> YYY<K,SCALAR>(this IHasXY<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Y, Y, Y, K, SCALAR>(); }
    public static FlexBl<K,D4,SCALAR> YYYY<K,SCALAR>(this IHasXY<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Y, Y, Y, Y, K, SCALAR>(); }
    public static FlexBl<K,D2,SCALAR> ZZ<K,SCALAR>(this IHasXYZ<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Z, Z, K, SCALAR>(); }
    public static FlexBl<K,D3,SCALAR> ZZZ<K,SCALAR>(this IHasXYZ<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Z, Z, Z, K, SCALAR>(); }
    public static FlexBl<K,D4,SCALAR> ZZZZ<K,SCALAR>(this IHasXYZ<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Z, Z, Z, Z, K, SCALAR>(); }
    public static FlexBl<K,D2,SCALAR> WW<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<W, W, K, SCALAR>(); }
    public static FlexBl<K,D3,SCALAR> WWW<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<W, W, W, K, SCALAR>(); }
    public static FlexBl<K,D4,SCALAR> WWWW<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<W, W, W, W, K, SCALAR>(); }

    public static FlexBl<K,D2,SCALAR> XY<K,SCALAR>(this IHasXY<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<X, Y, K, SCALAR>(); }
    public static FlexBl<K,D2,SCALAR> YX<K,SCALAR>(this IHasXY<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Y, X, K, SCALAR>(); }

    public static FlexBl<K,D2,SCALAR> YZ<K,SCALAR>(this IHasXYZ<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Y, Z, K, SCALAR>(); }
    public static FlexBl<K,D2,SCALAR> XZ<K,SCALAR>(this IHasXYZ<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<X, Z, K, SCALAR>(); }
    public static FlexBl<K,D2,SCALAR> ZY<K,SCALAR>(this IHasXYZ<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Z, Y, K, SCALAR>(); }
    public static FlexBl<K,D2,SCALAR> ZX<K,SCALAR>(this IHasXYZ<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Z, X, K, SCALAR>(); }

    public static FlexBl<K,D3,SCALAR> ZYX<K,SCALAR>(this IHasXYZ<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Z, Y, X, K, SCALAR>(); }
    public static FlexBl<K,D3,SCALAR> ZXY<K,SCALAR>(this IHasXYZ<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Z, X, Y, K, SCALAR>(); }
    public static FlexBl<K,D3,SCALAR> YZX<K,SCALAR>(this IHasXYZ<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Y, Z, X, K, SCALAR>(); }
    public static FlexBl<K,D3,SCALAR> XZY<K,SCALAR>(this IHasXYZ<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<X, Z, Y, K, SCALAR>(); }
    public static FlexBl<K,D3,SCALAR> YXZ<K,SCALAR>(this IHasXYZ<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Y, X, Z, K, SCALAR>(); }
    public static FlexBl<K,D3,SCALAR> XYZ<K,SCALAR>(this IHasXYZ<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<X, Y, Z, K, SCALAR>(); }

    public static FlexBl<K,D2,SCALAR> YW<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Y, W, K, SCALAR>(); }
    public static FlexBl<K,D2,SCALAR> ZW<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Z, W, K, SCALAR>(); }
    public static FlexBl<K,D2,SCALAR> XW<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<X, W, K, SCALAR>(); }
    public static FlexBl<K,D2,SCALAR> WY<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<W, Y, K, SCALAR>(); }
    public static FlexBl<K,D2,SCALAR> WZ<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<W, Z, K, SCALAR>(); }
    public static FlexBl<K,D2,SCALAR> WX<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<W, X, K, SCALAR>(); }

    public static FlexBl<K,D3,SCALAR> XYW<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<X, Y, W, K, SCALAR>(); }
    public static FlexBl<K,D3,SCALAR> XZW<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<X, Z, W, K, SCALAR>(); }
    public static FlexBl<K,D3,SCALAR> YXW<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Y, X, W, K, SCALAR>(); }
    public static FlexBl<K,D3,SCALAR> YZW<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Y, Z, W, K, SCALAR>(); }
    public static FlexBl<K,D3,SCALAR> ZXW<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Z, X, W, K, SCALAR>(); }
    public static FlexBl<K,D3,SCALAR> ZYW<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Z, Y, W, K, SCALAR>(); }

    public static FlexBl<K,D3,SCALAR> XWY<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<X, W, Y, K, SCALAR>(); }
    public static FlexBl<K,D3,SCALAR> XWZ<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<X, W, Z, K, SCALAR>(); }
    public static FlexBl<K,D3,SCALAR> YWX<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Y, W, X, K, SCALAR>(); }
    public static FlexBl<K,D3,SCALAR> YWZ<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Y, W, Z, K, SCALAR>(); }
    public static FlexBl<K,D3,SCALAR> ZWX<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Z, W, X, K, SCALAR>(); }
    public static FlexBl<K,D3,SCALAR> ZWY<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Z, W, Y, K, SCALAR>(); }

    public static FlexBl<K,D3,SCALAR> WXY<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<W, X, Y, K, SCALAR>(); }
    public static FlexBl<K,D3,SCALAR> WXZ<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<W, X, Z, K, SCALAR>(); }
    public static FlexBl<K,D3,SCALAR> WYX<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<W, Y, X, K, SCALAR>(); }
    public static FlexBl<K,D3,SCALAR> WYZ<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<W, Y, Z, K, SCALAR>(); }
    public static FlexBl<K,D3,SCALAR> WZX<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<W, Z, X, K, SCALAR>(); }
    public static FlexBl<K,D3,SCALAR> WZY<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<W, Z, Y, K, SCALAR>(); }

    public static FlexBl<K,D4,SCALAR> XYZW<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<X, Y, Z, W, K, SCALAR>(); }
    public static FlexBl<K,D4,SCALAR> XZYW<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<X, Z, Y, W, K, SCALAR>(); }
    public static FlexBl<K,D4,SCALAR> YXZW<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Y, X, Z, W, K, SCALAR>(); }
    public static FlexBl<K,D4,SCALAR> YZXW<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Y, Z, X, W, K, SCALAR>(); }
    public static FlexBl<K,D4,SCALAR> ZXYW<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Z, X, Y, W, K, SCALAR>(); }
    public static FlexBl<K,D4,SCALAR> ZYXW<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Z, Y, X, W, K, SCALAR>(); }

    public static FlexBl<K,D4,SCALAR> XYWZ<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<X, Y, W, Z, K, SCALAR>(); }
    public static FlexBl<K,D4,SCALAR> XZWY<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<X, Z, W, Y, K, SCALAR>(); }
    public static FlexBl<K,D4,SCALAR> YXWZ<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Y, X, W, Z, K, SCALAR>(); }
    public static FlexBl<K,D4,SCALAR> YZWX<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Y, Z, W, X, K, SCALAR>(); }
    public static FlexBl<K,D4,SCALAR> ZXWY<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Z, X, W, Y, K, SCALAR>(); }
    public static FlexBl<K,D4,SCALAR> ZYWX<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Z, Y, W, X, K, SCALAR>(); }

    public static FlexBl<K,D4,SCALAR> XWYZ<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<X, W, Y, Z, K, SCALAR>(); }
    public static FlexBl<K,D4,SCALAR> XWZY<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<X, W, Z, Y, K, SCALAR>(); }
    public static FlexBl<K,D4,SCALAR> YWXZ<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Y, W, X, Z, K, SCALAR>(); }
    public static FlexBl<K,D4,SCALAR> YWZX<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Y, W, Z, X, K, SCALAR>(); }
    public static FlexBl<K,D4,SCALAR> ZWXY<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Z, W, X, Y, K, SCALAR>(); }
    public static FlexBl<K,D4,SCALAR> ZWYX<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<Z, W, Y, X, K, SCALAR>(); }

    public static FlexBl<K,D4,SCALAR> WXYZ<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<W, X, Y, Z, K, SCALAR>(); }
    public static FlexBl<K,D4,SCALAR> WXZY<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<W, X, Z, Y, K, SCALAR>(); }
    public static FlexBl<K,D4,SCALAR> WYXZ<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<W, Y, X, Z, K, SCALAR>(); }
    public static FlexBl<K,D4,SCALAR> WYZX<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<W, Y, Z, X, K, SCALAR>(); }
    public static FlexBl<K,D4,SCALAR> WZXY<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<W, Z, X, Y, K, SCALAR>(); }
    public static FlexBl<K,D4,SCALAR> WZYX<K,SCALAR>(this IHasXYZW<K,SCALAR> V) where SCALAR : ValueBrand<K,SCALAR,K,D1,SCALAR> { return V.Sw<W, Z, Y, X, K, SCALAR>(); }
  }

}
namespace Bling.Core {
  using Bling.Matrices;
  public partial interface IDouble {
    /*
    FlexDoubleBl<DX> Swizzle<DX>(params int[] Indices) where DX : Dim<DX>;
    Double2Bl Swizzle(int Index0, int Index1);
    Double3Bl Swizzle(int Index0, int Index1, int Index2);
    Double4Bl Swizzle(int Index0, int Index1, int Index2, int Index3);
     */
  }


  /// <summary>
  /// Base class of all double-like numeric types.
  /// </summary>
  public abstract partial class DoubleBl<T, BRAND, D> : NumericBrand<T, BRAND, double, D, DoubleBl>, IHasX<double,DoubleBl>, IDouble<BRAND>
    where BRAND : DoubleBl<T, BRAND, D>
    where D : Dim<D> {
    public new FlexDoubleBl<DX> Swizzle<DX>(params int[] Indices) where DX : Dim<DX> {
      return new FlexDoubleBl<DX>(new SwizzleOp<DX>(Indices).Make(this));
    }
    public Double2Bl Swizzle(int Index0, int Index1) {
      return Swizzle<D2>(Index0, Index1);
    }
    public Double3Bl Swizzle(int Index0, int Index1, int Index2) {
      return Swizzle<D3>(Index0, Index1, Index2);
    }
    public Double4Bl Swizzle(int Index0, int Index1, int Index2, int Index3) {
      return Swizzle<D4>(Index0, Index1, Index2, Index3);
    }
  }
  public static partial class Swizzles {
    public static Double2Bl Sw<A, B>(this IHasXY<double, DoubleBl> V)
      where A : Y, new()
      where B : Y, new() {
      var Idx = new int[2];
      Idx[0] = (new A()).Index;
      Idx[1] = (new B()).Index;
      return V.Swizzle<D2>(Idx);
    }
    public static Double2Bl Sw<A, B>(this IHasXYZ<double, DoubleBl> V)
      where A : Z, new()
      where B : Z, new() {
      var Idx = new int[2];
      Idx[0] = (new A()).Index;
      Idx[1] = (new B()).Index;
      return V.Swizzle<D2>(Idx);
    }
    public static Double2Bl Sw<A, B>(this IHasXYZW<double, DoubleBl> V)
      where A : W, new()
      where B : W, new() {
      var Idx = new int[2];
      Idx[0] = (new A()).Index;
      Idx[1] = (new B()).Index;
      return V.Swizzle<D2>(Idx);
    }
    public static Double3Bl Sw<A, B, C>(this IHasXY<double, DoubleBl> V)
      where A : Y, new()
      where B : Y, new()
      where C : Y, new() {
      var Idx = new int[3];
      Idx[0] = (new A()).Index;
      Idx[1] = (new B()).Index;
      Idx[2] = (new C()).Index;
      return V.Swizzle<D3>(Idx);
    }
    public static Double3Bl Sw<A, B, C>(this IHasXYZ<double, DoubleBl> V)
      where A : Z, new()
      where B : Z, new()
      where C : Z, new() {
      var Idx = new int[3];
      Idx[0] = (new A()).Index;
      Idx[1] = (new B()).Index;
      Idx[2] = (new C()).Index;
      return V.Swizzle<D3>(Idx);
    }
    public static Double3Bl Sw<A, B, C>(this IHasXYZW<double, DoubleBl> V)
      where A : W, new()
      where B : W, new()
      where C : W, new() {
      var Idx = new int[3];
      Idx[0] = (new A()).Index;
      Idx[1] = (new B()).Index;
      Idx[2] = (new C()).Index;
      return V.Swizzle<D3>(Idx);
    }
    public static Double4Bl Sw<A, B, C, D>(this IHasXY<double, DoubleBl> V)
      where A : Y, new()
      where B : Y, new()
      where C : Y, new()
      where D : Y, new() {
      var Idx = new int[3];
      Idx[0] = (new A()).Index;
      Idx[1] = (new B()).Index;
      Idx[2] = (new C()).Index;
      Idx[3] = (new D()).Index;
      return V.Swizzle<D4>(Idx);
    }
    public static Double4Bl Sw<A, B, C, D>(this IHasXYZ<double, DoubleBl> V)
      where A : Z, new()
      where B : Z, new()
      where C : Z, new()
      where D : Z, new() {
      var Idx = new int[3];
      Idx[0] = (new A()).Index;
      Idx[1] = (new B()).Index;
      Idx[2] = (new C()).Index;
      Idx[3] = (new D()).Index;
      return V.Swizzle<D4>(Idx);
    }
    public static Double4Bl Sw<A, B, C, D>(this IHasXYZW<double, DoubleBl> V)
      where A : W, new()
      where B : W, new()
      where C : W, new()
      where D : W, new() {
      var Idx = new int[3];
      Idx[0] = (new A()).Index;
      Idx[1] = (new B()).Index;
      Idx[2] = (new C()).Index;
      Idx[3] = (new D()).Index;
      return V.Swizzle<D4>(Idx);
    }

    public static Double2Bl XX(this IHasX<double, DoubleBl>  V) { return V.Swizzle<D2>(0, 0); }
    public static Double3Bl XXX(this IHasX<double, DoubleBl> V) { return V.Swizzle<D3>(0, 0, 0); }
    public static Double4Bl XXXX(this IHasX<double, DoubleBl> V) { return V.Swizzle<D4>(0, 0, 0, 0); }
    public static Double2Bl YY(this IHasXY<double, DoubleBl> V) { return V.Sw<Y, Y>(); }
    public static Double3Bl YYY(this IHasXY<double, DoubleBl> V) { return V.Sw<Y, Y, Y>(); }
    public static Double4Bl YYYY(this IHasXY<double, DoubleBl> V) { return V.Sw<Y, Y, Y, Y>(); }
    public static Double2Bl ZZ(this IHasXYZ<double, DoubleBl> V) { return V.Sw<Z, Z>(); }
    public static Double3Bl ZZZ(this IHasXYZ<double, DoubleBl> V) { return V.Sw<Z, Z, Z>(); }
    public static Double4Bl ZZZZ(this IHasXYZ<double, DoubleBl> V) { return V.Sw<Z, Z, Z, Z>(); }
    public static Double2Bl WW(this IHasXYZW<double, DoubleBl> V) { return V.Sw<W, W>(); }
    public static Double3Bl WWW(this IHasXYZW<double, DoubleBl> V) { return V.Sw<W, W, W>(); }
    public static Double4Bl WWWW(this IHasXYZW<double, DoubleBl> V) { return V.Sw<W, W, W, W>(); }

    public static Double2Bl XY(this IHasXY<double, DoubleBl> V) { return V.Sw<X,Y>(); }
    public static Double2Bl YX(this IHasXY<double, DoubleBl> V) { return V.Sw<Y,X>(); }

    public static Double2Bl YZ(this IHasXYZ<double, DoubleBl> V) { return V.Sw<Y, Z>(); }
    public static Double2Bl XZ(this IHasXYZ<double, DoubleBl> V) { return V.Sw<X,Z>(); }
    public static Double2Bl ZY(this IHasXYZ<double, DoubleBl> V) { return V.Sw<Z,Y>(); }
    public static Double2Bl ZX(this IHasXYZ<double, DoubleBl> V) { return V.Sw<Z,X>(); }

    public static Double3Bl ZYX(this IHasXYZ<double, DoubleBl> V) { return V.Sw<Z,Y,X>(); }
    public static Double3Bl ZXY(this IHasXYZ<double, DoubleBl> V) { return V.Sw<Z,X,Y>(); }
    public static Double3Bl YZX(this IHasXYZ<double, DoubleBl> V) { return V.Sw<Y,Z,X>(); }
    public static Double3Bl XZY(this IHasXYZ<double, DoubleBl> V) { return V.Sw<X,Z,Y>(); }
    public static Double3Bl YXZ(this IHasXYZ<double, DoubleBl> V) { return V.Sw<Y,X,Z>(); }
    public static Double3Bl XYZ(this IHasXYZ<double,DoubleBl> V) { return V.Sw<X,Y,Z>(); }

    public static Double2Bl YW(this IHasXYZW<double, DoubleBl> V) { return V.Sw<Y, W>(); }
    public static Double2Bl ZW(this IHasXYZW<double, DoubleBl> V) { return V.Sw<Z, W>(); }
    public static Double2Bl XW(this IHasXYZW<double, DoubleBl> V) { return V.Sw<X, W>(); }
    public static Double2Bl WY(this IHasXYZW<double, DoubleBl> V) { return V.Sw<W, Y>(); }
    public static Double2Bl WZ(this IHasXYZW<double, DoubleBl> V) { return V.Sw<W, Z>(); }
    public static Double2Bl WX(this IHasXYZW<double, DoubleBl> V) { return V.Sw<W, X>(); }

    public static Double3Bl XYW(this IHasXYZW<double, DoubleBl> V) { return V.Sw<X, Y, W>(); }
    public static Double3Bl XZW(this IHasXYZW<double, DoubleBl> V) { return V.Sw<X, Z, W>(); }
    public static Double3Bl YXW(this IHasXYZW<double, DoubleBl> V) { return V.Sw<Y, X, W>(); }
    public static Double3Bl YZW(this IHasXYZW<double, DoubleBl> V) { return V.Sw<Y, Z, W>(); }
    public static Double3Bl ZXW(this IHasXYZW<double, DoubleBl> V) { return V.Sw<Z, X, W>(); }
    public static Double3Bl ZYW(this IHasXYZW<double, DoubleBl> V) { return V.Sw<Z, Y, W>(); }

    public static Double3Bl XWY(this IHasXYZW<double, DoubleBl> V) { return V.Sw<X, W, Y>(); }
    public static Double3Bl XWZ(this IHasXYZW<double, DoubleBl> V) { return V.Sw<X, W, Z>(); }
    public static Double3Bl YWX(this IHasXYZW<double, DoubleBl> V) { return V.Sw<Y, W, X>(); }
    public static Double3Bl YWZ(this IHasXYZW<double, DoubleBl> V) { return V.Sw<Y, W, Z>(); }
    public static Double3Bl ZWX(this IHasXYZW<double, DoubleBl> V) { return V.Sw<Z, W, X>(); }
    public static Double3Bl ZWY(this IHasXYZW<double, DoubleBl> V) { return V.Sw<Z, W, Y>(); }

    public static Double3Bl WXY(this IHasXYZW<double, DoubleBl> V) { return V.Sw<W, X, Y>(); }
    public static Double3Bl WXZ(this IHasXYZW<double, DoubleBl> V) { return V.Sw<W, X, Z>(); }
    public static Double3Bl WYX(this IHasXYZW<double, DoubleBl> V) { return V.Sw<W, Y, X>(); }
    public static Double3Bl WYZ(this IHasXYZW<double, DoubleBl> V) { return V.Sw<W, Y, Z>(); }
    public static Double3Bl WZX(this IHasXYZW<double, DoubleBl> V) { return V.Sw<W, Z, X>(); }
    public static Double3Bl WZY(this IHasXYZW<double, DoubleBl> V) { return V.Sw<W, Z, Y>(); }

    public static Double4Bl XYZW(this IHasXYZW<double, DoubleBl> V) { return V.Sw<X, Y, Z, W>(); }
    public static Double4Bl XZYW(this IHasXYZW<double, DoubleBl> V) { return V.Sw<X, Z, Y, W>(); }
    public static Double4Bl YXZW(this IHasXYZW<double, DoubleBl> V) { return V.Sw<Y, X, Z, W>(); }
    public static Double4Bl YZXW(this IHasXYZW<double, DoubleBl> V) { return V.Sw<Y, Z, X, W>(); }
    public static Double4Bl ZXYW(this IHasXYZW<double, DoubleBl> V) { return V.Sw<Z, X, Y, W>(); }
    public static Double4Bl ZYXW(this IHasXYZW<double, DoubleBl> V) { return V.Sw<Z, Y, X, W>(); }

    public static Double4Bl XYWZ(this IHasXYZW<double, DoubleBl> V) { return V.Sw<X, Y, W, Z>(); }
    public static Double4Bl XZWY(this IHasXYZW<double, DoubleBl> V) { return V.Sw<X, Z, W, Y>(); }
    public static Double4Bl YXWZ(this IHasXYZW<double, DoubleBl> V) { return V.Sw<Y, X, W, Z>(); }
    public static Double4Bl YZWX(this IHasXYZW<double, DoubleBl> V) { return V.Sw<Y, Z, W, X>(); }
    public static Double4Bl ZXWY(this IHasXYZW<double, DoubleBl> V) { return V.Sw<Z, X, W, Y>(); }
    public static Double4Bl ZYWX(this IHasXYZW<double, DoubleBl> V) { return V.Sw<Z, Y, W, X>(); }

    public static Double4Bl XWYZ(this IHasXYZW<double, DoubleBl> V) { return V.Sw<X, W, Y, Z>(); }
    public static Double4Bl XWZY(this IHasXYZW<double, DoubleBl> V) { return V.Sw<X, W, Z, Y>(); }
    public static Double4Bl YWXZ(this IHasXYZW<double, DoubleBl> V) { return V.Sw<Y, W, X, Z>(); }
    public static Double4Bl YWZX(this IHasXYZW<double, DoubleBl> V) { return V.Sw<Y, W, Z, X>(); }
    public static Double4Bl ZWXY(this IHasXYZW<double, DoubleBl> V) { return V.Sw<Z, W, X, Y>(); }
    public static Double4Bl ZWYX(this IHasXYZW<double, DoubleBl> V) { return V.Sw<Z, W, Y, X>(); }

    public static Double4Bl WXYZ(this IHasXYZW<double, DoubleBl> V) { return V.Sw<W, X, Y, Z>(); }
    public static Double4Bl WXZY(this IHasXYZW<double, DoubleBl> V) { return V.Sw<W, X, Z, Y>(); }
    public static Double4Bl WYXZ(this IHasXYZW<double, DoubleBl> V) { return V.Sw<W, Y, X, Z>(); }
    public static Double4Bl WYZX(this IHasXYZW<double, DoubleBl> V) { return V.Sw<W, Y, Z, X>(); }
    public static Double4Bl WZXY(this IHasXYZW<double, DoubleBl> V) { return V.Sw<W, Z, X, Y>(); }
    public static Double4Bl WZYX(this IHasXYZW<double, DoubleBl> V) { return V.Sw<W, Z, Y, X>(); }
  }
}
